/*
 ------------------------------------------------------------------------------
 Copyright (C) 2009-2011 Eternal Games.

 This file is part of the Eternal Tech source code.

 The Eternal Tech source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Eternal Tech source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Eternal Tech source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// cl_draw.cpp - Draw functions
//


#include "cl_local.h"
#include "client.h"


/*
 ==============================================================================

    DRAWING UTILITIES

 ==============================================================================
*/


/*
 ==================
 CL_FadeAlpha
 ==================
*/
byte *CL_FadeAlpha (const color_t color, int startTime, int totalTime, int fadeTime)
{
	static color_t   fadeColor;
	int				 time;
	float			 scale;

	time = cl.time - startTime;
	if (time >= totalTime)
		return NULL;

	if (totalTime - time < fadeTime && fadeTime != 0)
		scale = (float)(totalTime - time) * (1.0f / fadeTime);
	else
		scale = 1.0f;

	fadeColor[0] = color[0];
	fadeColor[1] = color[1];
	fadeColor[2] = color[2];
	fadeColor[3] = color[3] * scale;

	return fadeColor;
}

/*
 ==================
 CL_DrawChar
 ==================
*/
void CL_DrawChar (float x, float y, float size, int ch, const color_t color, fontSet_t *font, int flags)
{
	fontInfo_t	  *fontInfo;
	glyphInfo_t   *glyphInfo;
	float		  scale;

	if (size <= 0.0f || !ch)
		return;

	//if (!font)
	//	font = R_RegisterFont("_default");

	if (!font)
		font = cls.media.genericFont; // FIXME: Bad workaround for the renderer

	// Get the font
	if (size <= cl_smallFont->floatValue)
		fontInfo = &font->fontInfo[font_tMALL];
	else if (size >= cl_largeFont->floatValue)
		fontInfo = &font->fontInfo[FONT_LARGE];
	else
		fontInfo = &font->fontInfo[FONT_MEDIUM];

	// Set glyph scale
	scale = size * fontInfo->glyphScale;

	// Draw it
	glyphInfo = &fontInfo->glyphs[ch];

	R_DrawStretchPic(x, y - (glyphInfo->yAdjust * scale), glyphInfo->width * scale, glyphInfo->height * scale, glyphInfo->s1, glyphInfo->t1, glyphInfo->s2, glyphInfo->t2, color, glyphInfo->material);

	x += glyphInfo->xAdjust * scale;
}

/*
 ==================
 CL_DrawString

 TODO: Text align flags needs some more work
 ==================
*/
void CL_DrawString (float x, float y, float size, const char *string, const color_t color, fontSet_t *font, int flags)
{
	fontInfo_t	  *fontInfo;
	glyphInfo_t   *glyphInfo;
	float		  scale;
	char	      line[1024], *l;
	int			  length;
	int			  i, xx;

	if (size <= 0.0f || !string)
		return;

	//if (!font)
	//	font = R_RegisterFont("_default");

	if (!font)
		font = cls.media.genericFont; // FIXME: Bad workaround for the renderer

	// Get the font
	if (size <= cl_smallFont->floatValue)
		fontInfo = &font->fontInfo[font_tMALL];
	else if (size >= cl_largeFont->floatValue)
		fontInfo = &font->fontInfo[FONT_LARGE];
	else
		fontInfo = &font->fontInfo[FONT_MEDIUM];

	// Set glyph scale
	scale = size * fontInfo->glyphScale;

	// Get a string
	while (*string){
		length = 0;
		while (*string){
			if (*string == '\n' || *string == '\r')
			{
				string++;
				break;
			}
			else if (*string == '\t')
			{
				for (i = 0; i < 4; i++)
				{
					line[length++] = ' ';

					if (length == sizeof(line)-1)
						break;
				}

				string++;
			}
			else
				line[length++] = *string++;

			if (length == sizeof(line)-1)
				break;
		}
		line[length] = 0;

		xx = x; // FIXME: Bad workaround for the renderer

		// Align the text as appropriate
		if (flags & TAF_LEFT)
			xx = x;
		if (flags & TAF_CENTER)
			xx = x + ((SCREEN_WIDTH - (Q_PrintStrlen(line) * scale)) / 2);
		if (flags & TAF_RIGHT)
			xx = x + (SCREEN_WIDTH - (Q_PrintStrlen(line) * scale));

		// Draw each glyph
		l = line;
		while (*l){
			if (Q_IsColorString(l))
			{
				l += 2;
				continue;
			}

			glyphInfo = &fontInfo->glyphs[*l++];

			R_DrawStretchPic(xx, y - (glyphInfo->yAdjust * scale), glyphInfo->width * scale, glyphInfo->height * scale, glyphInfo->s1, glyphInfo->t1, glyphInfo->s2, glyphInfo->t2, color, glyphInfo->material);

			xx += glyphInfo->xAdjust * scale;
		}
	}
}

/*
 ==================
 CL_FillRect
 ==================
*/
void CL_FillRect (float x, float y, float w, float h, const color_t color)
{
	R_DrawStretchPic(x, y, w, h, 0.0f, 0.0f, 1.0f, 1.0f, color, cls.media.whiteMaterial);
}

/*
 ==================
 CL_DrawPic
 ==================
*/
void CL_DrawPic (float x, float y, float w, float h, const color_t color, struct material_t *material)
{
	if (!material)
		material = cls.media.whiteMaterial; // FIXME: Bad workaround for the renderer

	R_DrawStretchPic(x, y, w, h, 0.0f, 0.0f, 1.0f, 1.0f, color, material);
}


/*
 ==============================================================================

    2D DRAWING

 ==============================================================================
*/


static void CL_DrawLogo ()
{
	if (!cl_drawLogo->integerValue)
		return;
}

/*
 ==================
 CL_ScanForPlayerEntity

 TODO: Expand to support monsters
 ==================
*/
static void CL_ScanForPlayerEntity ()
{
	trace_t	trace;
	vec3_t	start, end;
	int		entNumber;

	VectorCopy(cl.renderView.viewOrigin, start);
	VectorMA(cl.renderView.viewOrigin, 8192, cl.renderView.viewAxis[0], end);

	trace = CL_Trace(start, vec3_origin, vec3_origin, end, cl.playernum+1, MASK_PLAYERSOLID, false, &entNumber);
	if (trace.fraction == 0.0f || trace.fraction == 1.0f)
		return;

	if (entNumber < 1 || entNumber > MAX_CLIENTS)
		return;   // Not a valid entity

	if (cl.entities[entNumber].current.modelindex != 255)
		return;   // Not a player, or invisible

	cl.crosshairEntTime = cl.time;
	cl.crosshairEntNumber = entNumber;
}

/*
 ==================
 CL_DrawCrosshair
 ==================
*/
static void CL_DrawCrosshair ()
{
	clientInfo_t   *ci;
	int			   crosshair;
	color_t		   color;
	byte		   *fadeColor;
	float		   x, y, w, h;

	// Select crosshair
	crosshair = (cl_drawCrosshair->integerValue - 1) % NUM_CROSSHAIRS;
	if (crosshair < 0)
		return;

	// Set dimensions and position
	w = cl_crosshairSize->integerValue;
	h = cl_crosshairSize->integerValue;

	x = cl_crosshairX->integerValue + ((SCREEN_WIDTH - w) * 0.5f);
	y = cl_crosshairY->integerValue + ((SCREEN_HEIGHT - h) * 0.5f);

	color[0] = colorTable[cl_crosshairColor->integerValue & Q_COLOR_MASK][0];
	color[1] = colorTable[cl_crosshairColor->integerValue & Q_COLOR_MASK][1];
	color[2] = colorTable[cl_crosshairColor->integerValue & Q_COLOR_MASK][2];
	color[3] = 255 * Clamp(cl_crosshairAlpha->floatValue, 0.0f, 1.0f);

	// Draw it
	CL_DrawPic(x, y, w, h, color, cl.media.crosshairMaterials[crosshair]);

	// Draw targets name, hp and level
	if (cl_crosshairNames->integerValue)
	{
		// Scan for a player entity
		CL_ScanForPlayerEntity();

		if (!cl.crosshairEntTime || !cl.crosshairEntNumber)
			return;

		ci = &cl.clientInfo[cl.crosshairEntNumber - 1];
		if (!ci->valid)
			return;

		// Set alpha
		fadeColor = CL_FadeAlpha(color, cl.crosshairEntTime, 1000, 250);
		if (!fadeColor)
		{
			cl.crosshairEntTime = 0;
			cl.crosshairEntNumber = 0;
			return;
		}

		// Draw it
		CL_DrawString(x+10, y + (h*2), 0.18f, ci->name, fadeColor, cls.media.genericFont, 0);
	}
}

/*
 ==================
 CL_DrawFPS
 ==================
*/
static void CL_DrawFPS ()
{
	color_t		color;
	static int	previousTime;
	int			time;
	int			total, fps;
	char		string[16];
	int			i;

	time = Sys_Milliseconds();

	cls2.fpsTimes[cls2.fpsIndex & (FPS_FRAMES - 1)] = time - previousTime;
	cls2.fpsIndex++;

	previousTime = time;

	if (!cl_drawFPS->integerValue || cls2.fpsIndex <= FPS_FRAMES)
		return;

	// Average multiple frames together to smooth changes out a bit
	total = 0;

	for (i = 0; i < FPS_FRAMES; i++)
		total += cls2.fpsTimes[i];

	if (total < 1)
		total = 1;

	fps = 1000 * FPS_FRAMES / total;
	if (fps > 1000)
		fps = 1000;

	// Draw it
	Str_SPrintf(string, sizeof(string), "%i FPS", fps);

	if (fps < 30)
		MakeRGBA(color, 255, 0, 0, 255);
	else if (fps < 60)
		MakeRGBA(color, 255, 255, 0, 255);
	else
		MakeRGBA(color, 255, 255, 255, 255);

	CL_DrawString(5, 15, 0.28f, string, color, cls.media.genericFont, 0);
}

/*
 ==================
 CL_ShowMaterial

 TODO: Fix the text position and surface flags
 ==================
*/
static void CL_ShowMaterial ()
{
	trace_t	trace;
	vec3_t	start, end;
	char	string[512];

	if (!cl_showMaterial->integerValue)
		return;

	VectorCopy(cl.renderView.viewOrigin, start);
	VectorMA(cl.renderView.viewOrigin, 8192, cl.renderView.viewAxis[0], end);

	if (cl_showMaterial->integerValue == 1)
	{
		trace = CL_Trace(start, vec3_origin, vec3_origin, end, cl.playernum+1, MASK_SOLID | MASK_WATER, true, NULL);
		if (trace.fraction == 0.0f || trace.fraction == 1.0f)
			return;
	}
	else
	{
		trace = CL_Trace(start, vec3_origin, vec3_origin, end, cl.playernum+1, MASK_ALL, true, NULL);
		if (trace.fraction == 0.0f || trace.fraction == 1.0f)
			return;
	}

	CL_DrawString(0, 300, 0.18f, "MATERIAL", colorTable[COLOR_GREEN], cls.media.genericFont, TAF_CENTER);
	CL_DrawString(0, 322, 0.18f, "SURFACE FLAGS", colorTable[COLOR_GREEN], cls.media.genericFont, TAF_CENTER);
	CL_DrawString(0, 344, 0.18f, "CONTENTS FLAGS", colorTable[COLOR_GREEN], cls.media.genericFont, TAF_CENTER);

	// Material
	Str_SPrintf(string, sizeof(string), "textures/%s", trace.surface->name);
	CL_DrawString(0, 310, 0.18f, string, colorTable[COLOR_WHITE], cls.media.genericFont, TAF_CENTER);

	// Surface flags
	if (trace.surface->flags)
	{
		string[0] = 0;

		if (trace.surface->flags & SURF_LIGHT)
			Str_Append(string, "LIGHT ", sizeof(string));
		if (trace.surface->flags & SURF_SLICK)
			Str_Append(string, "SLICK ", sizeof(string));
		if (trace.surface->flags & SURF_SKY)
			Str_Append(string, "SKY ", sizeof(string));
		if (trace.surface->flags & SURF_WARP)
			Str_Append(string, "WARP ", sizeof(string));
		if (trace.surface->flags & SURF_TRANS33)
			Str_Append(string, "TRANS33 ", sizeof(string));
		if (trace.surface->flags & SURF_TRANS66)
			Str_Append(string, "TRANS66 ", sizeof(string));
		if (trace.surface->flags & SURF_FLOWING)
			Str_Append(string, "FLOWING ", sizeof(string));
		if (trace.surface->flags & SURF_NODRAW)
			Str_Append(string, "NODRAW ", sizeof(string));

		string[Str_Length(string)-1] = 0;

		CL_DrawString(0, 332, 0.18f, string, colorTable[COLOR_WHITE], cls.media.genericFont, TAF_CENTER);
	}

	// Contents flags
	if (trace.contents)
	{
		string[0] = 0;

		if (trace.contents & CONTENTS_SOLID)
			Str_Append(string, "SOLID ", sizeof(string));
		if (trace.contents & CONTENTS_WINDOW)
			Str_Append(string, "WINDOW ", sizeof(string));
		if (trace.contents & CONTENTS_AUX)
			Str_Append(string, "AUX ", sizeof(string));
		if (trace.contents & CONTENTS_LAVA)
			Str_Append(string, "LAVA ", sizeof(string));
		if (trace.contents & CONTENTS_SLIME)
			Str_Append(string, "SLIME ", sizeof(string));
		if (trace.contents & CONTENTS_WATER)
			Str_Append(string, "WATER ", sizeof(string));
		if (trace.contents & CONTENTS_MIST)
			Str_Append(string, "MIST ", sizeof(string));

		if (!string[0])
			Str_Append(string, "\n", sizeof(string));
		else
			string[Str_Length(string)-1] = '\n';

		if (trace.contents & CONTENTS_AREAPORTAL)
			Str_Append(string, "AREAPORTAL ", sizeof(string));
		if (trace.contents & CONTENTS_PLAYERCLIP)
			Str_Append(string, "PLAYERCLIP ", sizeof(string));
		if (trace.contents & CONTENTS_MONSTERCLIP)
			Str_Append(string, "MONSTERCLIP ", sizeof(string));

		if (!string[0])
			Str_Append(string, "\n", sizeof(string));
		else
			string[Str_Length(string)-1] = '\n';

		if (trace.contents & CONTENTS_CURRENT_0)
			Str_Append(string, "CURRENT_0 ", sizeof(string));
		if (trace.contents & CONTENTS_CURRENT_90)
			Str_Append(string, "CURRENT_90 ", sizeof(string));
		if (trace.contents & CONTENTS_CURRENT_180)
			Str_Append(string, "CURRENT_180 ", sizeof(string));
		if (trace.contents & CONTENTS_CURRENT_270)
			Str_Append(string, "CURRENT_270 ", sizeof(string));
		if (trace.contents & CONTENTS_CURRENT_UP)
			Str_Append(string, "CURRENT_UP ", sizeof(string));
		if (trace.contents & CONTENTS_CURRENT_DOWN)
			Str_Append(string, "CURRENT_DOWN ", sizeof(string));

		if (!string[0])
			Str_Append(string, "\n", sizeof(string));
		else
			string[Str_Length(string)-1] = '\n';

		if (trace.contents & CONTENTS_ORIGIN)
			Str_Append(string, "ORIGIN ", sizeof(string));
		if (trace.contents & CONTENTS_MONSTER)
			Str_Append(string, "MONSTER ", sizeof(string));
		if (trace.contents & CONTENTS_DEADMONSTER)
			Str_Append(string, "DEADMONSTER ", sizeof(string));
		if (trace.contents & CONTENTS_DETAIL)
			Str_Append(string, "DETAIL ", sizeof(string));
		if (trace.contents & CONTENTS_TRANSLUCENT)
			Str_Append(string, "TRANSLUCENT ", sizeof(string));
		if (trace.contents & CONTENTS_LADDER)
			Str_Append(string, "LADDER ", sizeof(string));

		string[Str_Length(string)-1] = 0;

		CL_DrawString(0, 354, 0.18f, string, colorTable[COLOR_WHITE], cls.media.genericFont, TAF_CENTER);
	}
}

/*
 ==================
 CL_Draw2D
 ==================
*/
void CL_Draw2D ()
{
	// Draw the logo
	CL_DrawLogo();

	// Draw the crosshair
	CL_DrawCrosshair();

	// Draw frames rendered per second
	CL_DrawFPS();

	// Draw surface material infomation
	CL_ShowMaterial();
}








































// THIS WILL BE REPLACED LATER

/*
 ==================
 CL_DrawConChar
 ==================
*/
void CL_DrawConChar (int x, int y, int ch, const color_t color)
{
	float	col, row;

	ch &= 255;
	if (ch == ' ')
		return;

	col = (ch & 15) * 0.0625f;
	row = (ch >> 4) * 0.0625f;

	R_DrawStretchPic(x+1, y+2, 8, 16, col, row, col + 0.0625f, row + 0.0625f, colorTable[COLOR_BLACK], cls.media.charsetMaterial);
	R_DrawStretchPic(x, y, 8, 16, col, row, col + 0.0625f, row + 0.0625f, color, cls.media.charsetMaterial);
}

/*
 ==================
 CL_DrawConString
 ==================
*/
void CL_DrawConString (int x, int y, const char *string, const color_t color)
{
	color_t	currentColor;
	int		ch;
	float	col, row;

	*(uint *)currentColor = *(uint *)color;

	while (*string){
		if (Q_IsColorString(string))
		{
			*(uint *)currentColor = *(uint *)colorTable[Q_ColorIndex(*(string+1))];
			string += 2;
			continue;
		}

		ch = *string++;

		ch &= 255;
		if (ch != ' ')
		{
			col = (ch & 15) * 0.0625f;
			row = (ch >> 4) * 0.0625f;

			R_DrawStretchPic(x+1, y+2, 8, 16, col, row, col + 0.0625f, row + 0.0625f, colorTable[COLOR_BLACK], cls.media.charsetMaterial);
			R_DrawStretchPic(x, y, 8, 16, col, row, col + 0.0625f, row + 0.0625f, currentColor, cls.media.charsetMaterial);
		}

		x += 8;
	}
}